1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.math.random;
12 import core.stdc.stdlib;
13 
14 version(WebAssembly) extern(C) float JS_Math_random() @nogc nothrow;
15 version(PSVita) extern(C) int psv_rand() @nogc nothrow;
16 
17 class Random
18 {
19     @disable this();
20     
21     // version(Android)
22     // {
23     //     import std.random;
24     //     private __gshared std.random.Random randomGenerator;
25     // }
26     static void initialize()
27     {
28         version(WebAssembly){} else
29         {
30             import core.stdc.time;
31             srand(cast(uint)time(null));
32         }
33         // version(Android)
34         // {
35         //     import std.random;
36         //     randomGenerator = std.random.Random(std.random.unpredictableSeed());
37         // }
38     }
39 
40     @nogc nothrow
41     {
42         static float rangef(float min, float max)
43         {
44             version(WebAssembly){return JS_Math_random() * (max-min) + min;}
45             else version(PSVita){return (cast(float)psv_rand() / RAND_MAX) * (max-min) + min;}
46             //else version(Android){return std.random.uniform(cast(int)min, cast(int)max, randomGenerator);}
47             else
48                 return (cast(float)rand() / RAND_MAX) * (max-min) + min;
49         }
50         static int range(int min, int max)
51         {
52             return cast(int)rangef(min, max);
53         }
54         static uint rangeu(uint min, uint max)
55         {
56             return cast(uint)rangef(min, max);
57         }
58         static ubyte rangeub(ubyte min, ubyte max)
59         {
60             return cast(ubyte)rangef(min, max);
61         }
62     }
63 
64     /**
65     *   This function gets a container and returns a random value from it.
66     *   It may not receive any weight, so, it will be normally distributed (I expect)
67     *   If it receives less weights than it has values, the last value will contain a weight equals
68     *   to 1 - sum(weights)
69     *   The weights must sum up to 1.0
70     */
71     static T select(T)(in T[] container, float[] weights = []) @nogc nothrow
72     {
73         if(weights.length == 0)
74         {
75             int min = 0;
76             int max = cast(int)(container.length) - 1;
77             int index = range(min, max);
78 
79             return container[index];
80         }
81 
82         float currentSum = 0;
83         float selectedValue = rangef(0.0, 1.0);
84         
85         for(int i = 0; i < weights.length; i++)
86         {
87             if(selectedValue >= currentSum && selectedValue <= currentSum+weights[i])
88                 return container[i];
89             currentSum+= weights[i];
90         }
91         return container[$-1];
92     }
93     
94 }